/**
 * \file
 */
#include "../kfs_math.hpp"
#include <cstdio>
#include <iostream>
#include <stdint.h>
#include <string>
#include <vector>

using std::cerr;  using std::cin;  using std::cout;  using std::endl;
using std::ios;
using std::string;  using std::vector;

// Shims
uint32_t const mb_blockNumBytes = 4096;

/**
 * file_getIndices
 * Copied from kfs_impl.cpp.
 */
void file_getIndices(uint32_t fileBlockNumber, vector<uint32_t>& indices)
{
    indices.clear();
    // How many block pointers in each index block?
    // Example: A 4 KB index block holds 1024 32-bit pointers.
    uint32_t const n = mb_blockNumBytes / sizeof(uint32_t);
    unsigned const log_n = floor_log2(n);
    //uint32_t const mask_low  = (1 << floorLog2(n)) - 1;
    uint32_t const mask_low  = n - 1;
    if(fileBlockNumber >= n*n + n + 12)
    {
        // Triple indirection
        uint32_t acc = fileBlockNumber - n*n - n - 12;
        indices.push_back(14);
        indices.push_back((acc >> (2*log_n)) & mask_low);
        indices.push_back((acc >> log_n)     & mask_low);
        indices.push_back( acc               & mask_low);
    }
    else if(fileBlockNumber >= n + 12)
    {
        // Double indirection
        uint32_t acc = fileBlockNumber - n - 12;
        indices.push_back(13);
        indices.push_back((acc >> log_n) & mask_low);
        indices.push_back( acc           & mask_low);
    }
    else if(fileBlockNumber >= 12)
    {
        // Single indirection
        indices.push_back(12);
        indices.push_back(fileBlockNumber - 12);
    }
    else
    {
        // Zero indirection
        indices.push_back(fileBlockNumber);
    }
}


/**
 * Test harness for getIndices.
 */
void test_getIndices()
{
    // Number of pointers per block.
    uint32_t const n = mb_blockNumBytes / sizeof(uint32_t);
    uint32_t const
        //direct_begin = 0,
        single_begin = 12,
        double_begin = n+12,
        triple_begin = n*n + n + 12;
    uint32_t const bns[] = {
        // Direct blocks
        0, 1, 2,
        // Single indirect blocks
        single_begin, single_begin + 1,
        double_begin - 1,
        // Double indirect blocks
        double_begin, double_begin + 1,
        triple_begin - 2, triple_begin - 1,
        // Triple indirect blocks
        triple_begin, triple_begin + 1
    };
    for(size_t i = 0; i < sizeof(bns)/sizeof(uint32_t); ++i)
    {
        std::vector<uint32_t> indices;
        file_getIndices(bns[i], indices);
        printf("Block %5d: ", bns[i]);
        for(std::vector<uint32_t>::const_iterator i = indices.begin();
            i != indices.end(); ++i)
        {
            if( i != indices.begin())
                printf(", ");
            printf("%4d", *i);
        }
        printf("\n");
    }
}


int main()
{
    test_getIndices();
}
